package com.tongfusoft.web.core.data;

import java.io.IOException;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.JsonMappingException;

import com.tongfusoft.utils.ReflectionUtils;
import com.tongfusoft.web.core.Constant;
import com.tongfusoft.web.core.annotation.FieldName;
import com.tongfusoft.web.core.annotation.LogDesc;
import com.tongfusoft.web.core.exception.JSONException;

public abstract class BaseData implements Serializable {
	/**
	 * Logger for this class
	 */
	@JsonIgnore
	private static final Log logger = LogFactory.getLog(BaseData.class);

	/**
	 * 
	 */
	@JsonIgnore
	private static final long serialVersionUID = 25916750516752114L;

	/**
	 * 创建时间
	 */
	@FieldName(value="CREATED_DATE")
	protected Date createdDate;
	/**
	 * 更新时间
	 */
	@FieldName(value="LAST_UPD_DATE")
	protected Date lastUpdDate;
	
	/**
	 * 创建人
	 */
	@FieldName(value="CREATED_BY")
	protected String createdBy;
	
	/**
	 * 更新人
	 */
	@FieldName(value="LAST_UPD_BY")
	protected String lastUpdBy;
	
	
	public static final String FIELD_CREATEDBY = "createdBy";
	public static final String FIELD_LASTUPDBY = "lastUpdBy";

	public static final String FIELD_CREATEDDATE = "createdDate";
	public static final String FIELD_LASTUPDDATE = "lastUpdDate";
	
	/**
	 * 封装成json格式的字符串
	 * 
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	@JsonIgnore
	public String getJsonStr() {
		try {
			return Constant.OBJECTMAPPER.writeValueAsString(this);
		} catch (JsonGenerationException e) {
			logger.error("getJsonStr error:" + e.getMessage());
			throw new JSONException(e);
		} catch (JsonMappingException e) {
			logger.error("getJsonStr error:" + e.getMessage());
			throw new JSONException(e);
		} catch (IOException e) {
			logger.error("getJsonStr error:" + e.getMessage());
			throw new JSONException(e);
		}
		// return JSONObject.fromObject(this.getAllPropertyValue()).toString();
	}

	/*
	 * private Map getAllPropertyValue() throws IllegalAccessException,
	 * InvocationTargetException, NoSuchMethodException { Map<String, Object>
	 * map = new HashMap<String, Object>(); List<Field> fields = new
	 * ArrayList<Field>(); Class clazz = this.getClass(); while (clazz !=
	 * Object.class && clazz != BaseData.class) { for (Field field :
	 * clazz.getDeclaredFields()) fields.add(field); clazz =
	 * clazz.getSuperclass(); } for (Field field : fields) { // 对于每个属性，获取属性名
	 * map.put(field.getName(), PropertyUtils.getSimpleProperty(this,
	 * field.getName())); }
	 * 
	 * return map; }
	 */

	@JsonIgnore
	private Map getAllValue() {
		try {
			Map map = Constant.OBJECTMAPPER.readValue(getJsonStr(), Map.class);
			return map;
		} catch (JsonParseException e) {
			logger.error("getAllValue error:" + e.getMessage());
			throw new JSONException(e);
		} catch (JsonMappingException e) {
			logger.error("getAllValue error:" + e.getMessage());
			throw new JSONException(e);
		} catch (IOException e) {
			logger.error("getAllValue error:" + e.getMessage());
			throw new JSONException(e);
		}
	}

	/**
	 * 获取新增的Map
	 * 
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	@JsonIgnore
	public Map<String, Object> getInsertMap() {
		Map map = getAllValue();
		map = this.putDateValue(map);
		
		if (map.get(BaseData.FIELD_CREATEDDATE) == null) {
			map.put(BaseData.FIELD_CREATEDDATE, new Date());
			//新增时也增加修改时间
			map.put(BaseData.FIELD_LASTUPDDATE, new Date());
		}

		return map;
	}
	
	/**
	 * 填充Date类型的数据
	 * @param map
	 * @return
	 */
	private Map<String,Object> putDateValue(Map map){
		//获取所有的field
		Set<Field> fields = ReflectionUtils.getDeclaredFields(this);
		Iterator<Field> iter = fields.iterator();
		while(iter.hasNext()){
			Field field = iter.next();
			if(StringUtils.equals(field.getType().getName(),Date.class.getName())){
				map.put(field.getName(), this.getFieldValue(field.getName()));
			}
		}
		
		return map;
	}

	/**
	 * 获取修改的Map
	 * 
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	@JsonIgnore
	public Map<String, Object> getUpdateMap() {
		Map map = getAllValue();
		map = this.putDateValue(map);

		if (map.get(BaseData.FIELD_LASTUPDDATE) == null) {
			map.put(BaseData.FIELD_LASTUPDDATE, new Date());
		}

		return map;
	}

	/**
	 * 获取主键的属性名
	 * 
	 * @return
	 */
	@JsonIgnore
	public abstract String getPkName();

	/**
	 * 获取删除的Map
	 * 
	 * @return
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	@JsonIgnore
	public Map<String, Object> getRemoveMap() {
		try {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put(this.getPkName(),
					PropertyUtils.getSimpleProperty(this, this.getPkName()));
			return map;
		} catch (IllegalAccessException e) {
			logger.error("getRemoveMap error:" + e.getMessage());
			throw new JSONException(e);
		} catch (InvocationTargetException e) {
			logger.error("getRemoveMap error:" + e.getMessage());
			throw new JSONException(e);
		} catch (NoSuchMethodException e) {
			logger.error("getRemoveMap error:" + e.getMessage());
			throw new JSONException(e);
		}
	}

	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	public Date getLastUpdDate() {
		return lastUpdDate;
	}

	public void setLastUpdDate(Date lastUpdDate) {
		this.lastUpdDate = lastUpdDate;
	}
	
	public String getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}

	public String getLastUpdBy() {
		return lastUpdBy;
	}

	public void setLastUpdBy(String lastUpdBy) {
		this.lastUpdBy = lastUpdBy;
	}

	@JsonIgnore
	public abstract String getTableName();

	@JsonIgnore
	public String getAddTag() {
		return "/common#" + this.getTableName();
	}

	@JsonIgnore
	public String getUpdateTag() {
		return "/common#" + this.getTableName();
	}

	@JsonIgnore
	public String getRemoveTag() {
		return "/common#" + this.getTableName();
	}
	
	/**
	 * 获取主键的值
	 * @return
	 */
	public String getPkValue(){
		return (String)ReflectionUtils.getFieldValue(this, this.getPkName());
	}
	
	/**
	 * 设置主键的值
	 * @param value
	 */
	public void setPkValue(String value){
		ReflectionUtils.setFieldValue(this, this.getPkName(), value);
	}
	
	/**
	 * 根据属性名获取属性值
	 * @param fieldName
	 * @return
	 */
	public Object getFieldValue(String fieldName){
		return ReflectionUtils.getFieldValue(this, fieldName);
	}
	
	/**
	 * 返回属性和字段的映射
	 * @return
	 */
	public Map<String,String> getFieldMap(){
		Map<String,String> result = new HashMap<String,String>();
		Set<Field> fields = ReflectionUtils.getDeclaredFields(this);
		Iterator<Field> iter = fields.iterator();
		while(iter.hasNext()){
			Field field = iter.next();
			if(field.isAnnotationPresent(FieldName.class)){
				FieldName annotation = field.getAnnotation(FieldName.class);
				result.put(field.getName(), annotation.value());
			}else{
				result.put(field.getName(), this.getFieldName(field.getName()));
			}
		}
		
		return result;
	}
	
	private String getFieldName(String propName){
		StringBuffer sb = new StringBuffer();
		
		for(int i=0;i<propName.length();i++){
			char c = propName.charAt(i);
			
			if(Character.isUpperCase(c)){
				sb.append("_");
			}
			
			sb.append(c);
		}
		
		return sb.toString().toUpperCase();
	}
}
